package server;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Database {
	HashMap<String, ArrayList<FileType>> database;
	private final String PATH = "journaler/";
	private final File directory = new File(PATH); 
	private int currentJournal = 0;
	
	public static void main(String[] args){
		new Database();
	}
	
	public Database(){		
		database = new HashMap<String, ArrayList<FileType>>();
		ArrayList<FileType> a = new ArrayList<FileType>();
		File f = new File("certificates/test/");
		
		String list = "";		
		String[] fileList = f.list();
        for (int i = 0; i < fileList.length; i++){
        	if(fileList[i].endsWith(".jks")){
        		list += fileList[i] +"::";
        	}        		
        }
        list = list.replaceAll(".jks", "");
        list = list.replaceAll("server", "");		
		String[] entries = list.split("::");
		for(int i = 0; i < entries.length; i++){
			if(entries[i].length() > 0){
				database.put(entries[i], new ArrayList<Database.FileType>());
			}
		}

		database.put("EarNoseThroat", new ArrayList<Database.FileType>());
		database.put("Surgery", new ArrayList<Database.FileType>());
		database.put("Gov", new ArrayList<Database.FileType>());
		
		populateDatabase();	
		
	}
	
	
	/**
	 * Adds a file bound to this username. If the file exists, it is replaces, otherwise it it created.
	 * @param username
	 * @param file
	 */
	public boolean addFileToUser(String username, String division, String filename, String content){				
		ArrayList<FileType> list = new ArrayList<FileType>();
		list = database.get(username);				
		File f = new File(PATH+filename);		
		System.out.println(f.getPath());
		String[] users = getUsersFromFile(f);
		File temp = new File(PATH+"temp.txt");
		try {
			FileOutputStream fos = new FileOutputStream(temp);
			fos.write(content.getBytes());
			fos.close();
		} catch (IOException e1) {}
		String[] newUsers = getUsersFromFile(temp);
		temp.delete();
		if(users[0] != null && users[1] != null && users[2] != null && users[3] != null){
			if(!users[0].equals(newUsers[0]) || !users[1].equals(newUsers[1]) ||
					!users[2].equals(newUsers[2]) || !users[3].equals(newUsers[3])){
				return false;
			}
		}else{
			return false;
		}
		try{
			FileOutputStream fout = new FileOutputStream(f);		
			fout.write(content.getBytes());
			fout.close();
			FileType ft = new FileType(f, true);																
			list.add(ft);
			
			FileType ftDiv = new FileType(f, false);
			list = database.get(division);				
			if(list.contains(ftDiv)){
				list.remove(list.indexOf(ftDiv));				
			}
			list.add(ftDiv);
			
			
		} catch(IOException e){
			e.printStackTrace();
		}
		return true;
	}
	

	/**
	 * Adds a new file to a doctor, and all associated users i.e patients, the division and the nurse to the database.
	 * This method also generates a filename for the new journal. 
	 * @param username
	 * @param division
	 * @param patientName
	 * @param nurseName
	 * @return
	 */
	public String[] addNewFileToUser(String username, String division, String patientName, String nurseName){	
		ArrayList<FileType> list = database.get(username);	
		String content = getJournalStub(username, patientName, nurseName, division);
		String filename = generateFileName(patientName);
		File f = new File(PATH+filename);
		System.out.println("Added: "+f.getPath());
		try{
			FileOutputStream fout = new FileOutputStream(f);				
			f.createNewFile();
			fout.write(content.getBytes());
			fout.close();
			//Add to Doctor
			FileType ft = new FileType(f, true);
			list.add(ft);
			//Add to Nurse
			list = database.get(nurseName);
			FileType ftNurse = new FileType(f, true);
			list.add(ftNurse);				
			//Add to Patient
			list = database.get(patientName);			
			FileType ftPatient = new FileType(f, false);
			list.add(ftPatient);	
			//Add to division
			list = database.get(division);
			list.add(ftPatient);	
			//Add to FBI
			list = database.get("FBI");
			list.add(new FileType(f, false));
		} catch(IOException e){
			e.printStackTrace();
		}
		String[] info = new String[2];
		info[0] = filename;
		info[1] = content;
		return info;		
	}
	
	public boolean containsUser(String name){
		return database.containsKey(name);
	}
	
	/**
	 * Get's a file from the specific user. Returns null if the file isn't bound to this username.
	 * @param username
	 * @param file
	 * @return
	 */
	public String getFileFromUser(String username, String filename, String division){
		ArrayList<FileType> list = database.get(division);
		File f = new File(PATH+filename);		
		int i =list.indexOf(new FileType(f, false));		
		if(i > -1){
			return readFile(list.get(i).file);
		}	
		list = database.get(username);
		f = new File(PATH+filename);		
		i =list.indexOf(new FileType(f, false));		
		if(i > -1){
			return readFile(list.get(i).file);
		}	
		
		return null;
	}
	
	
	/**
	 * Get's all the journals in the database separated by "::". Good to use for Government users
	 * @return
	 */
	public String getAllFilesForFBI(){
		String list = "";		
		String[] fileList = directory.list();
        for (int i = 0; i < fileList.length; i++){
        	if(fileList[i].endsWith(".txt"))
        		list += fileList[i] +"::";
        }
		return list;
	}
	
	/**
	 * Returns a list of files accessible files for this username, seperated by "::"
	 * @param username
	 * @return
	 */
	public String getListOfWritableFiles(String username){		
		ArrayList<FileType> list = database.get(username);
		String s = "";
		for(FileType file : list){
			if(file.isWritable)
				s += file.file.getName() +"::";
		}
		return s;		
	}
	
	public String getListOfAllFiles(String divisionOrPatientName, String username){
		String writable = getListOfWritableFiles(username);
		ArrayList<FileType> list = database.get(divisionOrPatientName);
		String s = "";
		for(FileType file : list){
			s += file.file.getName() +"::";
		}
		String[] files = writable.split("::");
		for(int i = 0; i < files.length; i++){
			if(!s.contains(files[i])){
				s = s.concat(files[i]+"::");
			}
		}
		return s;
	}
	
	/**
	 * Removes a file from the database. All users bound to this file will no longer be.
	 * @param text the file to be removed.
	 */
	public void removeFile(String filename) {
		Iterator itr = database.entrySet().iterator();
		File file = new File(PATH+filename);
		FileType ft = new FileType(file, false);
		while(itr.hasNext()){
			Entry<String, ArrayList<FileType>> entry = (Entry<String, ArrayList<FileType>>) itr.next();
			entry.getValue().remove(ft);	
		}
		System.out.println(file.delete());
		
	}
	
	public String getDivisionFromFile(String filename){	
		File f = new File(PATH+filename);		
		return readDivision(f);	
	}
	
	
	
	private String generateFileName(String patientName){		
		return "Journal"+currentJournal+"-"+patientName+".txt";
	}
	
	
	private void populateDatabase(){		
		String[] fileList = directory.list();
		
        for (int i = 0; i < fileList.length; i++){
        	if(fileList[i].endsWith(".txt")){
        		File f = new File(PATH+fileList[i]); 
        		Pattern p = Pattern.compile("\\d+");
        		Matcher m = p.matcher(f.getName()); 
        		while (m.find()) {
        		  if(Integer.parseInt(m.group())>currentJournal)
        		  		currentJournal = Integer.parseInt(m.group());
        		}
        		if(f.getName().equals("Journal7-Bosse.txt"))
        			System.out.println("röv");
        		String[] users = getUsersFromFile(f);          		
    			//Add to Doctor
    			FileType ft = new FileType(f, true);
    			database.get(users[0]).add(ft);    
    			//Add to division
    			FileType ftPatient = new FileType(f, false);
    			database.get(users[1]).add(ftPatient);
    			//Add to Patient
    			database.get(users[2]).add(ftPatient);
    			//Add to Nurse    			
    			FileType ftNurse = new FileType(f, true);
    			database.get(users[3]).add(ftNurse); 
    			//Add to FBI
    			database.get("FBI").add(new FileType(f, false));
    			System.out.println("Added: "+f.getPath()); 
        	}
        }
	}
	
	/**
	 * returns Doctor, division, patient, nurse
	 * in that order.
	 * @param f
	 * @return
	 */
	private String[] getUsersFromFile(File f){
		String[] users = new String[4];		
		try {
	    	BufferedReader in = new BufferedReader(new FileReader(f));
		    String str;
		    while ((str = in.readLine()) != null) {
		    	String[] line;
		        if(str.startsWith("Patient")){
		        	line = str.split(":");
		        	users[2] = line[1].trim();        		        
		        }else if(str.startsWith("Doktor") && !str.startsWith("Doktorns")){
		        	line = str.split(":");
		        	users[0] = line[1].trim();
		        }else if(str.startsWith("Sjuksyster")){
		        	line = str.split(":");
		        	users[3] = line[1].trim();
		        }else if(str.startsWith("Avdelning")){
		        	line = str.split(":");
		        	users[1] = line[1].trim();
		        }
		    }	     		
	    }catch (IOException e){
	    	e.printStackTrace();
	    }
		
		return users;
	}
	
	private String readFile(File f){
		String content = "";
	    try {
	    	BufferedReader in = new BufferedReader(new FileReader(f));
		    String str;
		    while ((str = in.readLine()) != null) {
		        content += str+"\n";
		    }	     		
	    }catch (IOException e){
	    	e.printStackTrace();
	    }
		return content;
	}
	
	private String readDivision(File f){
		String content = "";
	    try {
	    	BufferedReader in = new BufferedReader(new FileReader(f));
		    String str;
		    while ((str = in.readLine()) != null) {
		    	String[] line = str.split("Avdelning:");
		    	if(line.length > 1){
		    		content = line[1].replaceAll(" ", "");
		    	}		       
		    }	     		
	    }catch (IOException e){
	    	e.printStackTrace();
	    }
		return content;
	}
		
	
	private String getJournalStub(String doctorName, String patientName, String nurseName, String division){
		currentJournal++;
		String s = "JOURNAL No "+currentJournal+".\n\n"
			+"Patient: "+patientName+"\n"
			+"PersonNummer: \n"
			+"Doktor: "+doctorName+"\n"
			+"Sjuksyster: "+nurseName+"\n"
			+"Avdelning: "+division+"\n"
			+"Symptom: \n"
			+"Doktorns anteckningar: ";
		return s;
	}
	
	
	public void removeFileFromUser(String filename, String division) {
		Iterator itr = database.keySet().iterator();
		File file = new File(PATH+filename);
		FileType ft = new FileType(file, false);
		while(itr.hasNext()){
			String user = (String) itr.next();
			if(getFileFromUser(user, filename, division) != null){
				
			}	
		}
		System.out.println(file.delete());
		
	}
	
	
	private class FileType {
		private File file;
		private boolean isWritable;
		
		public FileType(File f, boolean isWritable){
			file = f;
			this.isWritable = isWritable;
		}
		
		@Override
		public boolean equals(Object o){
			FileType ft = (FileType) o;
			
			return file.equals(ft.file);
		}
	}
}
